home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / RTrace 1.0 / source / object.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-04  |  23.8 KB  |  756 lines  |  [TEXT/KAHL]

  1. /*
  2.  * Copyright (c) 1988, 1992 Antonio Costa, INESC-Norte.
  3.  * All rights reserved.
  4.  *
  5.  * This code received contributions from the following people:
  6.  *
  7.  *  Roman Kuchkuda      - basic ray tracer
  8.  *  Mark VandeWettering - MTV ray tracer
  9.  *  Augusto Sousa       - overall, shading model
  10.  *
  11.  * Redistribution and use in source and binary forms are permitted
  12.  * provided that the above copyright notice and this paragraph are
  13.  * duplicated in all such forms and that any documentation,
  14.  * advertising materials, and other materials related to such
  15.  * distribution and use acknowledge that the software was developed
  16.  * by Antonio Costa, at INESC-Norte. The name of the author and
  17.  * INESC-Norte may not be used to endorse or promote products derived
  18.  * from this software without specific prior written permission.
  19.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  21.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  22.  */
  23. #include "defs.h"
  24. #include "extern.h"
  25. #include "pp_ext.h"
  26.  
  27. /**********************************************************************
  28.  *    RAY TRACING - Scene (Objects) - Version 7.3.1                   *
  29.  *                                                                    *
  30.  *    MADE BY    : Antonio Costa, INESC-Norte, October 1988           *
  31.  *    ADAPTED BY : Antonio Costa, INESC-Norte, June 1989              *
  32.  *    MODIFIED BY: Antonio Costa, INESC-Norte, July 1992              *
  33.  **********************************************************************/
  34.  
  35. #define CREATE_OBJECT(type, object_data)\
  36. do {\
  37.   ALLOCATE(object[objects], object_struct, 1);\
  38.   object[objects]->id = objects;\
  39.   object[objects]->surface_id = surface_id;\
  40.   object[objects]->refraction = refraction;\
  41.   ALLOCATE(object[objects]->min, xyz_struct, 1);\
  42.   ALLOCATE(object[objects]->max, xyz_struct, 1);\
  43.   object[objects]->transf = NULL;\
  44.   object[objects]->inv_transf = NULL;\
  45.   object[objects]->texture = NULL;\
  46.   object[objects]->texture_modify_normal = FALSE;\
  47.   object[objects]->object_type = type;\
  48.   object[objects]->data = (void_ptr) object_data;\
  49. } while (0)
  50.  
  51. void
  52. get_sphere()
  53. {
  54.   int             surface_id;
  55.   real            value, refraction, radius;
  56.   xyz_struct      center;
  57.   sphere_ptr      sphere;
  58.  
  59.   get_valid(scene, &value, 1.0, (real) surfaces,
  60.             "OBJECT (SPHERE) SURFACE ID");
  61.   surface_id = PRED(ROUND(value));
  62.   get_valid(scene, &value, 1.0, REFRACTION_FACTOR_MAX,
  63.             "OBJECT (SPHERE) REFRACTION Factor");
  64.   refraction = value;
  65.   get_valid(scene, &value, X_MIN, X_MAX, "OBJECT (SPHERE) CENTER X");
  66.   center.x = value;
  67.   get_valid(scene, &value, Y_MIN, Y_MAX, "OBJECT (SPHERE) CENTER Y");
  68.   center.y = value;
  69.   get_valid(scene, &value, Z_MIN, Z_MAX, "OBJECT (SPHERE) CENTER Z");
  70.   center.z = value;
  71.   get_valid(scene, &value, ROUNDOFF, X_MAX * 0.5, "OBJECT (SPHERE) Radius");
  72.   radius = value;
  73.   ADVANCE(scene);
  74.   /* Create Sphere */
  75.   ALLOCATE(sphere, sphere_struct, 1);
  76.   STRUCT_ASSIGN(sphere->center, center);
  77.   sphere->radius = radius;
  78.   sphere->radius2 = SQR(radius);
  79.   CREATE_OBJECT(SPHERE_TYPE, sphere);
  80. }
  81. void
  82. get_box()
  83. {
  84.   int             surface_id;
  85.   real            value, refraction;
  86.   xyz_struct      center, size;
  87.   box_ptr         box;
  88.  
  89.   get_valid(scene, &value, 1.0, (real) surfaces,
  90.             "OBJECT (BOX) SURFACE ID");
  91.   surface_id = PRED(ROUND(value));
  92.   get_valid(scene, &value, 1.0, REFRACTION_FACTOR_MAX,
  93.             "OBJECT (BOX) REFRACTION Factor");
  94.   refraction = value;
  95.   get_valid(scene, &value, X_MIN, X_MAX, "OBJECT (BOX) CENTER X");
  96.   center.x = value;
  97.   get_valid(scene, &value, Y_MIN, Y_MAX, "OBJECT (BOX) CENTER Y");
  98.   center.y = value;
  99.   get_valid(scene, &value, Z_MIN, Z_MAX, "OBJECT (BOX) CENTER Z");
  100.   center.z = value;
  101.   get_valid(scene, &value, ROUNDOFF, X_MAX * 0.5, "OBJECT (BOX) SIZE X");
  102.   size.x = value;
  103.   get_valid(scene, &value, ROUNDOFF, Y_MAX * 0.5, "OBJECT (BOX) SIZE Y");
  104.   size.y = value;
  105.   get_valid(scene, &value, ROUNDOFF, Z_MAX * 0.5, "OBJECT (BOX) SIZE Z");
  106.   size.z = value;
  107.   ADVANCE(scene);
  108.   /* Create Box */
  109.   ALLOCATE(box, box_struct, 1);
  110.   STRUCT_ASSIGN(box->center, center);
  111.   STRUCT_ASSIGN(box->size, size);
  112.   CREATE_OBJECT(BOX_TYPE, box);
  113. }
  114. void
  115. get_patch()
  116. {
  117.   int             surface_id, i, vertices;
  118.   real            value, refraction;
  119.   xyz_struct      origin, scale;
  120.   patch_ptr       patch;
  121.   vertex_ptr      vertex_top, vertex_bottom, vertex;
  122.   char            name[STRING_MAX];
  123.   file_ptr        patch_file;
  124.  
  125.   get_valid(scene, &value, 1.0, (real) surfaces,
  126.             "OBJECT (PATCH) SURFACE ID");
  127.   surface_id = PRED(ROUND(value));
  128.   get_valid(scene, &value, 1.0, REFRACTION_FACTOR_MAX,
  129.             "OBJECT (PATCH) REFRACTION Factor");
  130.   refraction = value;
  131.   get_valid(scene, &value, X_MIN, X_MAX, "OBJECT (PATCH) ORIGIN X");
  132.   origin.x = value;
  133.   get_valid(scene, &value, Y_MIN, Y_MAX, "OBJECT (PATCH) ORIGIN Y");
  134.   origin.y = value;
  135.   get_valid(scene, &value, Z_MIN, Z_MAX, "OBJECT (PATCH) ORIGIN Z");
  136.   origin.z = value;
  137.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX, "OBJECT (PATCH) SCALE X");
  138.   scale.x = value;
  139.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX, "OBJECT (PATCH) SCALE Y");
  140.   scale.y = value;
  141.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX, "OBJECT (PATCH) SCALE Z");
  142.   scale.z = value;
  143.   READ_STRING(scene, name);
  144.   ADVANCE(scene);
  145.   if ((name[0] == '-') AND(name[1] == EOT))
  146.     patch_file = scene;
  147.   else
  148.   {
  149.     OPEN(patch_file, name, READ_TEXT);
  150.     if (IO_status != IO_OK)
  151.     {
  152.       WRITE(results, "Error: unable to open PATCH (%s)\n", name);
  153.       HALT;
  154.     }
  155.   }
  156.   vertices = 0;
  157.   vertex_top = NULL;
  158.   while (NOT END_OF_LINE(patch_file))
  159.   {
  160.     ALLOCATE(patch, patch_struct, 1);
  161.     for (i = 0; i < 12; POSINC(i))
  162.     {
  163.       get_valid(patch_file, &value, 1.0, INFINITY,
  164.                 "OBJECT (PATCH) VERTEX ID");
  165.       patch->p[i] = vertex_pointer(ROUND(value), &vertices,
  166.                                    &vertex_top, &vertex_bottom);
  167.     }
  168.     ADVANCE(patch_file);
  169.     if (objects >= OBJECTS_MAX)
  170.       runtime_abort("too many OBJECTS");
  171.     /* Create Patch */
  172.     CREATE_OBJECT(PATCH_TYPE, patch);
  173.     POSINC(objects);
  174.   }
  175.   ADVANCE(patch_file);
  176.   POSDEC(objects);
  177.   patch->vertex = vertex_top;
  178.   vertex = vertex_top;
  179.   i = 0;
  180.   while (NOT END_OF_LINE(patch_file))
  181.   {
  182.     if (vertex == NULL)
  183.       runtime_abort("no OBJECT (PATCH) VERTEX Coordinates");
  184.     POSINC(i);
  185.     if (i > vertices)
  186.       runtime_abort("too many OBJECT (PATCH) VERTEX Coordinates");
  187.     get_valid(patch_file, &value, X_MIN, X_MAX, "OBJECT (PATCH) VERTEX X");
  188.     vertex->coords.x = value * scale.x + origin.x;
  189.     get_valid(patch_file, &value, Y_MIN, Y_MAX, "OBJECT (PATCH) VERTEX Y");
  190.     vertex->coords.y = value * scale.y + origin.y;
  191.     get_valid(patch_file, &value, Z_MIN, Z_MAX, "OBJECT (PATCH) VERTEX Z");
  192.     vertex->coords.z = value * scale.z + origin.z;
  193.     vertex = (vertex_ptr) (vertex->next);
  194.     ADVANCE(patch_file);
  195.   }
  196.   if (i < vertices)
  197.     runtime_abort("not enough OBJECT (PATCH) VERTEX Coordinates");
  198.   if (patch_file != scene)
  199.     CLOSE(patch_file);
  200.   else
  201.     ADVANCE(scene);
  202. }
  203. void
  204. get_cone()
  205. {
  206.   int             surface_id;
  207.   real            value, refraction, base_radius, apex_radius, k;
  208.   xyz_struct      base, apex, temp;
  209.   cone_ptr        cone;
  210.  
  211.   get_valid(scene, &value, 1.0, (real) surfaces,
  212.             "OBJECT (CONE) SURFACE ID");
  213.   surface_id = PRED(ROUND(value));
  214.   get_valid(scene, &value, 1.0, REFRACTION_FACTOR_MAX,
  215.             "OBJECT (CONE) REFRACTION Factor");
  216.   refraction = value;
  217.   get_valid(scene, &value, X_MIN, X_MAX, "OBJECT (CONE) BASE X");
  218.   base.x = value;
  219.   get_valid(scene, &value, Y_MIN, Y_MAX, "OBJECT (CONE) BASE Y");
  220.   base.y = value;
  221.   get_valid(scene, &value, Z_MIN, Z_MAX, "OBJECT (CONE) BASE Z");
  222.   base.z = value;
  223.   get_valid(scene, &value, ROUNDOFF, X_MAX * 0.5,
  224.             "OBJECT (CONE) BASE Radius");
  225.   base_radius = value;
  226.   get_valid(scene, &value, X_MIN, X_MAX, "OBJECT (CONE) APEX X");
  227.   apex.x = value;
  228.   get_valid(scene, &value, Y_MIN, Y_MAX, "OBJECT (CONE) APEX Y");
  229.   apex.y = value;
  230.   get_valid(scene, &value, Z_MIN, Z_MAX, "OBJECT (CONE) APEX Z");
  231.   apex.z = value;
  232.   get_valid(scene, &value, ROUNDOFF, X_MAX * 0.5,
  233.             "OBJECT (CONE) APEX Radius");
  234.   apex_radius = value;
  235.   if (apex_radius > base_radius)
  236.     runtime_abort("bad OBJECT (CONE) APEX Radius");
  237.   ADVANCE(scene);
  238.   /* Create Cone / Cylinder */
  239.   ALLOCATE(cone, cone_struct, 1);
  240.   STRUCT_ASSIGN(cone->base, base);
  241.   STRUCT_ASSIGN(cone->apex, apex);
  242.   cone->base_radius = base_radius;
  243.   cone->apex_radius = apex_radius;
  244.   cone->w.x = apex.x - base.x;
  245.   cone->w.y = apex.y - base.y;
  246.   cone->w.z = apex.z - base.z;
  247.   cone->height = LENGTH(cone->w);
  248.   if (cone->height < ROUNDOFF)
  249.     runtime_abort("bad OBJECT (CONE) APEX and BASE");
  250.   NORMALIZE(cone->w);
  251.   cone->slope = (apex_radius - base_radius) / cone->height;
  252.   cone->base_d = -DOT_PRODUCT(base, cone->w);
  253.   if (ABS(cone->w.z) > 1.0 - ROUNDOFF)
  254.   {
  255.     temp.x = 0.0;
  256.     temp.y = 1.0;
  257.     temp.z = 0.0;
  258.   } else
  259.   {
  260.     temp.x = 0.0;
  261.     temp.y = 0.0;
  262.     temp.z = 1.0;
  263.   }
  264.   CROSS_PRODUCT(cone->u, cone->w, temp);
  265.   NORMALIZE(cone->u);
  266.   CROSS_PRODUCT(cone->v, cone->u, cone->w);
  267.   cone->min_d = DOT_PRODUCT(cone->w, base);
  268.   cone->max_d = DOT_PRODUCT(cone->w, apex);
  269.   if (cone->max_d < cone->min_d)
  270.   {
  271.     k = cone->max_d;
  272.     cone->max_d = cone->min_d;
  273.     cone->min_d = k;
  274.   }
  275.   CREATE_OBJECT(CONE_TYPE, cone);
  276. }
  277. typedef
  278. struct
  279. {
  280.   vertex_ptr     *point;
  281.   void_ptr        next;
  282. } data_struct;
  283. typedef
  284. data_struct    *data_ptr;
  285.  
  286. void
  287. get_polygon()
  288. {
  289.   int             surface_id, i, j, first, vertices;
  290.   real            value, refraction;
  291.   xyz_struct      origin, scale;
  292.   polygon_ptr     polygon;
  293.   vertex_ptr      vertex_top, vertex_bottom, vertex;
  294.   data_ptr        data_top, data_bottom, data;
  295.   char            name[STRING_MAX];
  296.   file_ptr        poly_file;
  297.  
  298.   get_valid(scene, &value, 1.0, (real) surfaces,
  299.             "OBJECT (POLYGON) SURFACE ID");
  300.   surface_id = PRED(ROUND(value));
  301.   get_valid(scene, &value, 1.0, REFRACTION_FACTOR_MAX,
  302.             "OBJECT (POLYGON) REFRACTION Factor");
  303.   refraction = value;
  304.   get_valid(scene, &value, X_MIN, X_MAX, "OBJECT (POLYGON) ORIGIN X");
  305.   origin.x = value;
  306.   get_valid(scene, &value, Y_MIN, Y_MAX, "OBJECT (POLYGON) ORIGIN Y");
  307.   origin.y = value;
  308.   get_valid(scene, &value, Z_MIN, Z_MAX, "OBJECT (POLYGON) ORIGIN Z");
  309.   origin.z = value;
  310.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX,
  311.             "OBJECT (POLYGON) SCALE X");
  312.   scale.x = value;
  313.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX,
  314.             "OBJECT (POLYGON) SCALE Y");
  315.   scale.y = value;
  316.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX,
  317.             "OBJECT (POLYGON) SCALE Z");
  318.   scale.z = value;
  319.   READ_STRING(scene, name);
  320.   ADVANCE(scene);
  321.   if ((name[0] == '-') AND(name[1] == EOT))
  322.     poly_file = scene;
  323.   else
  324.   {
  325.     OPEN(poly_file, name, READ_TEXT);
  326.     if (IO_status != IO_OK)
  327.     {
  328.       WRITE(results, "Error: unable to open POLYGON (%s)\n", name);
  329.       HALT;
  330.     }
  331.   }
  332.   first = objects;
  333.   data_top = NULL;
  334.   vertices = 0;
  335.   vertex_top = NULL;
  336.   while (NOT END_OF_LINE(poly_file))
  337.   {
  338.     ALLOCATE(polygon, polygon_struct, 1);
  339.     ALLOCATE(data, data_struct, 1);
  340.     if (data_top == NULL)
  341.       data_top = data;
  342.     else
  343.       data_bottom->next = (void_ptr) data;
  344.     data_bottom = data;
  345.     get_valid(poly_file, &value, 3.0, (real) MAXINT,
  346.               "OBJECT (POLYGON) VERTICES Polygon");
  347.     polygon->points = PRED(ROUND(value));
  348.     ALLOCATE(data->point, vertex_ptr, SUCC(polygon->points));
  349.     ALLOCATE(polygon->coords, array1, SUCC(polygon->points));
  350.     for (i = 0; i <= polygon->points; POSINC(i))
  351.     {
  352.       get_valid(poly_file, &value, 1.0, INFINITY,
  353.                 "OBJECT (POLYGON) VERTEX ID");
  354.       data->point[i] = vertex_pointer(ROUND(value), &vertices,
  355.                                       &vertex_top, &vertex_bottom);
  356.     }
  357.     data->next = NULL;
  358.     ADVANCE(poly_file);
  359.     if (objects >= OBJECTS_MAX)
  360.       runtime_abort("too many OBJECTS");
  361.     /* Create Polygon */
  362.     CREATE_OBJECT(POLYGON_TYPE, polygon);
  363.     POSINC(objects);
  364.  
  365. #ifdef THINK_C
  366.  
  367.     /* On the mac, we update the sub_progress bar periodically to show the number
  368.         of objects read */
  369.     if (status_dialog_visible) set_progress_bar_value(objects);
  370.  
  371. #endif
  372.  
  373.     PROCESS_MAC_EVENT
  374.  
  375.   }
  376.   ADVANCE(poly_file);
  377.   POSDEC(objects);
  378.   vertex = vertex_top;
  379.   i = 0;
  380.   while (NOT END_OF_LINE(poly_file))
  381.   {
  382.     if (vertex == NULL)
  383.       runtime_abort("no OBJECT (POLYGON) VERTEX Coordinates");
  384.     POSINC(i);
  385.     if (i > vertices)
  386.       runtime_abort("too many OBJECT (POLYGON) VERTEX Coordinates");
  387.     get_valid(poly_file, &value, X_MIN, X_MAX,
  388.               "OBJECT (POLYGON) VERTEX X");
  389.     vertex->coords.x = value * scale.x + origin.x;
  390.     get_valid(poly_file, &value, Y_MIN, Y_MAX,
  391.               "OBJECT (POLYGON) VERTEX Y");
  392.     vertex->coords.y = value * scale.y + origin.y;
  393.     get_valid(poly_file, &value, Z_MIN, Z_MAX,
  394.               "OBJECT (POLYGON) VERTEX Z");
  395.     vertex->coords.z = value * scale.z + origin.z;
  396.     vertex = (vertex_ptr) (vertex->next);
  397.     ADVANCE(poly_file);
  398.   }
  399.   if (i < vertices)
  400.     runtime_abort("not enough OBJECT (POLYGON) VERTEX Coordinates");
  401.   vertex_bottom->next = NULL;
  402.   data = data_top;
  403.  
  404. #ifdef THINK_C
  405.  
  406.     /* On the mac, we change the status text to show we're generating a polygon */
  407.     if (status_dialog_visible) set_status_text("\pGenerating Polygon…");
  408.  
  409.     /* Set the bar to show the loop progress */
  410.     if (objects != first)
  411.         set_sub_progress_bar_max(objects-first);
  412.  
  413. #endif
  414.  
  415.   for (i = first; i <= objects; POSINC(i))
  416.   {
  417.     polygon = (polygon_ptr) object[i]->data;
  418.     for (j = 0; j <= polygon->points; POSINC(j))
  419.     {
  420.       polygon->coords[j][0] = data->point[j]->coords.x;
  421.       polygon->coords[j][1] = data->point[j]->coords.y;
  422.       polygon->coords[j][2] = data->point[j]->coords.z;
  423.     }
  424.     data_top = data;
  425.     data = (data_ptr) (data->next);
  426.     FREE(data_top);
  427.  
  428. #ifdef THINK_C
  429.  
  430.     /* On the mac, we set the sub-progress bar to show loop progress */
  431.     if (status_dialog_visible) set_sub_progress_bar_value(i-first);
  432.  
  433.     PROCESS_MAC_EVENT
  434.  
  435. #endif
  436.  
  437.   }
  438.   
  439. #ifdef THINK_C
  440.  
  441.     /* On the mac, we change the status text to show we're cleaning up */
  442.     if (status_dialog_visible) set_status_text("\pCleaning up after Polygon…");
  443.  
  444.     /* Set the bar to show the loop progress */
  445.     set_sub_progress_bar_max(vertices);
  446.     i = 0;
  447.  
  448. #endif
  449.  
  450.   while (vertex_top != NULL)
  451.   {
  452.     vertex = vertex_top;
  453.     vertex_top = (vertex_ptr) (vertex_top->next);
  454.     FREE(vertex);
  455.  
  456. #ifdef THINK_C
  457.  
  458.     /* On the mac, we set the sub_progress bar to show vertex freeing progress */
  459.     if (status_dialog_visible) set_sub_progress_bar_value(++i);
  460.  
  461. #endif
  462.  
  463.   }
  464.   if (poly_file != scene)
  465.     CLOSE(poly_file);
  466.   else
  467.     ADVANCE(scene);
  468.  
  469. #ifdef THINK_C
  470.  
  471.     /* On the mac, we change the status text to show we're reading objects again */
  472.     if (status_dialog_visible)
  473.         {
  474.         set_status_text("\pReading Objects…");
  475.     
  476.         /* And set the sub-progress bar back to zero */
  477.         set_sub_progress_bar_value(0);
  478.         }
  479.  
  480. #endif
  481.  
  482. }
  483. void
  484. get_triangle()
  485. {
  486.   int             surface_id, i;
  487.   real            value, refraction;
  488.   xyz_struct      origin, scale;
  489.   triangle_ptr    triangle;
  490.   char            name[STRING_MAX];
  491.   file_ptr        tri_file;
  492.  
  493.   get_valid(scene, &value, 1.0, (real) surfaces,
  494.             "OBJECT (TRIANGLE) SURFACE ID");
  495.   surface_id = PRED(ROUND(value));
  496.   get_valid(scene, &value, 1.0, REFRACTION_FACTOR_MAX,
  497.             "OBJECT (TRIANGLE) REFRACTION Factor");
  498.   refraction = value;
  499.   get_valid(scene, &value, X_MIN, X_MAX, "OBJECT (TRIANGLE) ORIGIN X");
  500.   origin.x = value;
  501.   get_valid(scene, &value, Y_MIN, Y_MAX, "OBJECT (TRIANGLE) ORIGIN Y");
  502.   origin.y = value;
  503.   get_valid(scene, &value, Z_MIN, Z_MAX, "OBJECT (TRIANGLE) ORIGIN Z");
  504.   origin.z = value;
  505.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX,
  506.             "OBJECT (TRIANGLE) SCALE X");
  507.   scale.x = value;
  508.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX,
  509.             "OBJECT (TRIANGLE) SCALE Y");
  510.   scale.y = value;
  511.   get_valid(scene, &value, SCALE_MIN, SCALE_MAX,
  512.             "OBJECT (TRIANGLE) SCALE Z");
  513.   scale.z = value;
  514.   READ_STRING(scene, name);
  515.   ADVANCE(scene);
  516.   if ((name[0] == '-') AND(name[1] == EOT))
  517.     tri_file = scene;
  518.   else
  519.   {
  520.     OPEN(tri_file, name, READ_TEXT);
  521.     if (IO_status != IO_OK)
  522.     {
  523.       WRITE(results, "Error: unable to open TRIANGLE (%s)\n", name);
  524.       HALT;
  525.     }
  526.   }
  527.   while (NOT END_OF_LINE(tri_file))
  528.   {
  529.     ALLOCATE(triangle, triangle_struct, 1);
  530.     for (i = 0; i < 3; POSINC(i))
  531.     {
  532.       get_valid(tri_file, &value, X_MIN, X_MAX,
  533.                 "OBJECT (TRIANGLE) VERTEX Coord X");
  534.       triangle->coords[i].x = value * scale.x + origin.x;
  535.       get_valid(tri_file, &value, Y_MIN, Y_MAX,
  536.                 "OBJECT (TRIANGLE) VERTEX Coord Y");
  537.       triangle->coords[i].y = value * scale.y + origin.y;
  538.       get_valid(tri_file, &value, Z_MIN, Z_MAX,
  539.                 "OBJECT (TRIANGLE) VERTEX Coord Z");
  540.       triangle->coords[i].z = value * scale.z + origin.z;
  541.       get_valid(tri_file, &value, X_MIN, X_MAX,
  542.                 "OBJECT (TRIANGLE) VERTEX Normal X");
  543.       triangle->normal[i].x = value;
  544.       get_valid(tri_file, &value, Y_MIN, Y_MAX,
  545.                 "OBJECT (TRIANGLE) VERTEX Normal Y");
  546.       triangle->normal[i].y = value;
  547.       get_valid(tri_file, &value, Z_MIN, Z_MAX,
  548.                 "OBJECT (TRIANGLE) VERTEX Normal Z");
  549.       triangle->normal[i].z = value;
  550.       if (LENGTH(triangle->normal[i]) < ROUNDOFF)
  551.         runtime_abort("no OBJECT (TRIANGLE) VERTEX Normal");
  552.     }
  553.     ADVANCE(tri_file);
  554.     if (objects >= OBJECTS_MAX)
  555.       runtime_abort("too many OBJECTS");
  556.     /* Create Triangle */
  557.     CREATE_OBJECT(TRIANGLE_TYPE, triangle);
  558.     POSINC(objects);
  559.   }
  560.   POSDEC(objects);
  561.   if (tri_file != scene)
  562.     CLOSE(tri_file);
  563.   else
  564.     ADVANCE(scene);
  565. }
  566. void
  567. get_text()
  568. {
  569.   real            value;
  570.   char            name[STRING_MAX];
  571.   file_ptr        text_file;
  572.  
  573.   get_valid(scene, &value, 1.0, (real) surfaces,
  574.             "OBJECT (TEXT) SURFACE ID");
  575.   pp_surface_id = PRED(ROUND(value));
  576.   get_valid(scene, &value, 1.0, REFRACTION_FACTOR_MAX,
  577.             "OBJECT (TEXT) REFRACTION Factor");
  578.   pp_refraction = value;
  579.   READ_STRING(scene, name);
  580.   ADVANCE(scene);
  581.   if ((name[0] == '-') AND(name[1] == EOT))
  582.     text_file = scene;
  583.   else
  584.   {
  585.     OPEN(text_file, name, READ_TEXT);
  586.     if (IO_status != IO_OK)
  587.     {
  588.       WRITE(results, "Error: unable to open TEXT (%s)\n", name);
  589.       HALT;
  590.     }
  591.   }
  592.   /* Create Text */
  593.   POSDEC(objects);
  594.   get_pp_obj(text_file);
  595.   if (text_file != scene)
  596.     CLOSE(text_file);
  597. }
  598.  
  599. void
  600. get_csg()
  601. {
  602.   int             surface_id;
  603.   real            value, refraction;
  604.   csg_ptr         csg;
  605.   int             op;
  606.  
  607.   get_valid(scene, &value, 0.0, (real) surfaces,
  608.             "OBJECT (CSG) SURFACE ID");
  609.   surface_id = PRED(ROUND(value));
  610.   get_valid(scene, &value, 0.0, REFRACTION_FACTOR_MAX,
  611.             "OBJECT (CSG) REFRACTION Factor");
  612.   if (value < 1.0 - ROUNDOFF)
  613.     refraction = -1.0;
  614.   else
  615.     refraction = value;
  616.   get_valid(scene, &value, (real) CSG_UNION, (real) CSG_INTERSECTION,
  617.         "OBJECT (CSG) OPERATION");
  618.   op = ROUND(value);
  619.   ADVANCE(scene);
  620.   /* Create CSG */
  621.   ALLOCATE(csg, csg_struct, 1);
  622.   switch (op)
  623.   {
  624.   case CSG_UNION:
  625.     csg->op = CSG_UNION;
  626.     break;
  627.   case CSG_SUBTRACTION:
  628.     csg->op = CSG_SUBTRACTION;
  629.     break;
  630.   case CSG_INTERSECTION:
  631.     csg->op = CSG_INTERSECTION;
  632.     break;
  633.   }
  634.   CREATE_OBJECT(CSG_TYPE, csg);
  635. }
  636.  
  637. void
  638. get_list()
  639. {
  640.   int             surface_id;
  641.   real            value, refraction;
  642.   list_ptr        list;
  643.   int             op;
  644.  
  645.   get_valid(scene, &value, 0.0, (real) surfaces,
  646.             "OBJECT (LIST) SURFACE ID");
  647.   surface_id = PRED(ROUND(value));
  648.   get_valid(scene, &value, 0.0, REFRACTION_FACTOR_MAX,
  649.             "OBJECT (LIST) REFRACTION Factor");
  650.   if (value < 1.0 - ROUNDOFF)
  651.     refraction = -1.0;
  652.   else
  653.     refraction = value;
  654.   ADVANCE(scene);
  655.   /* Create List */
  656.   ALLOCATE(list, list_struct, 1);
  657.   CREATE_OBJECT(LIST_TYPE, list);
  658. }
  659.  
  660. #define MULTIPLY(result, first, second, index, coord)\
  661. do {\
  662.   result[index].coord = first[index].x * second[0].coord +\
  663.                         first[index].y * second[1].coord +\
  664.                         first[index].z * second[2].coord +\
  665.                         first[index].w * second[3].coord;\
  666. } while (0)
  667.  
  668. void
  669. get_object_transform(scene_objects, first_object, last_object)
  670.   int             scene_objects, *first_object, *last_object;
  671. {
  672.   boolean         null_transf;
  673.   int             i, id;
  674.   real            value;
  675.   boolean         first_transf;
  676.   xyzw_ptr        transf, new_transf;
  677.  
  678.   get_valid(scene, &value, 0.0, (real) scene_objects, "OBJECT ID");
  679.   id = PRED(ROUND(value));
  680.   if (id < 0)
  681.     id = PRED(scene_objects);
  682.   ALLOCATE(transf, xyzw_struct, 4);
  683.   null_transf = TRUE;
  684.   get_valid(scene, &(transf[0].x), X_MIN, X_MAX, "TRANSFORM X0");
  685.   null_transf = null_transf AND ABS(transf[0].x) < ROUNDOFF;
  686.   get_valid(scene, &(transf[0].y), Y_MIN, Y_MAX, "TRANSFORM Y0");
  687.   null_transf = null_transf AND ABS(transf[0].y) < ROUNDOFF;
  688.   get_valid(scene, &(transf[0].z), Z_MIN, Z_MAX, "TRANSFORM Z0");
  689.   null_transf = null_transf AND ABS(transf[0].z) < ROUNDOFF;
  690.   get_valid(scene, &(transf[0].w), W_MIN, W_MAX, "TRANSFORM W0");
  691.   null_transf = null_transf AND ABS(transf[0].w) < ROUNDOFF;
  692.   get_valid(scene, &(transf[1].x), X_MIN, X_MAX, "TRANSFORM X1");
  693.   null_transf = null_transf AND ABS(transf[1].x) < ROUNDOFF;
  694.   get_valid(scene, &(transf[1].y), Y_MIN, Y_MAX, "TRANSFORM Y1");
  695.   null_transf = null_transf AND ABS(transf[1].y) < ROUNDOFF;
  696.   get_valid(scene, &(transf[1].z), Z_MIN, Z_MAX, "TRANSFORM Z1");
  697.   null_transf = null_transf AND ABS(transf[1].z) < ROUNDOFF;
  698.   get_valid(scene, &(transf[1].w), W_MIN, W_MAX, "TRANSFORM W1");
  699.   null_transf = null_transf AND ABS(transf[1].w) < ROUNDOFF;
  700.   get_valid(scene, &(transf[2].x), X_MIN, X_MAX, "TRANSFORM X2");
  701.   null_transf = null_transf AND ABS(transf[2].x) < ROUNDOFF;
  702.   get_valid(scene, &(transf[2].y), Y_MIN, Y_MAX, "TRANSFORM Y2");
  703.   null_transf = null_transf AND ABS(transf[2].y) < ROUNDOFF;
  704.   get_valid(scene, &(transf[2].z), Z_MIN, Z_MAX, "TRANSFORM Z2");
  705.   null_transf = null_transf AND ABS(transf[2].z) < ROUNDOFF;
  706.   get_valid(scene, &(transf[2].w), W_MIN, W_MAX, "TRANSFORM W2");
  707.   null_transf = null_transf AND ABS(transf[2].w) < ROUNDOFF;
  708.   get_valid(scene, &(transf[3].x), X_MIN, X_MAX, "TRANSFORM X3");
  709.   null_transf = null_transf AND ABS(transf[3].x) < ROUNDOFF;
  710.   get_valid(scene, &(transf[3].y), Y_MIN, Y_MAX, "TRANSFORM Y3");
  711.   null_transf = null_transf AND ABS(transf[3].y) < ROUNDOFF;
  712.   get_valid(scene, &(transf[3].z), Z_MIN, Z_MAX, "TRANSFORM Z3");
  713.   null_transf = null_transf AND ABS(transf[3].z) < ROUNDOFF;
  714.   get_valid(scene, &(transf[3].w), W_MIN, W_MAX, "TRANSFORM W3");
  715.   null_transf = null_transf AND ABS(transf[3].w) < ROUNDOFF;
  716.   ADVANCE(scene);
  717.   if (null_transf)
  718.   {
  719.     FREE(transf);
  720.     return;
  721.   }
  722.   first_transf = FALSE;
  723.   for (i = first_object[id]; i <= last_object[id]; POSINC(i))
  724.   {
  725.     if (object[i]->transf == NULL)
  726.     {
  727.       object[i]->transf = transf;
  728.       first_transf = TRUE;
  729.     } else
  730.     {
  731.       ALLOCATE(new_transf, xyzw_struct, 4);
  732.       MULTIPLY(new_transf, transf, object[i]->transf, 0, x);
  733.       MULTIPLY(new_transf, transf, object[i]->transf, 0, y);
  734.       MULTIPLY(new_transf, transf, object[i]->transf, 0, z);
  735.       MULTIPLY(new_transf, transf, object[i]->transf, 0, w);
  736.       MULTIPLY(new_transf, transf, object[i]->transf, 1, x);
  737.       MULTIPLY(new_transf, transf, object[i]->transf, 1, y);
  738.       MULTIPLY(new_transf, transf, object[i]->transf, 1, z);
  739.       MULTIPLY(new_transf, transf, object[i]->transf, 1, w);
  740.       MULTIPLY(new_transf, transf, object[i]->transf, 2, x);
  741.       MULTIPLY(new_transf, transf, object[i]->transf, 2, y);
  742.       MULTIPLY(new_transf, transf, object[i]->transf, 2, z);
  743.       MULTIPLY(new_transf, transf, object[i]->transf, 2, w);
  744.       MULTIPLY(new_transf, transf, object[i]->transf, 3, x);
  745.       MULTIPLY(new_transf, transf, object[i]->transf, 3, y);
  746.       MULTIPLY(new_transf, transf, object[i]->transf, 3, z);
  747.       MULTIPLY(new_transf, transf, object[i]->transf, 3, w);
  748.       if (i == last_object[id])
  749.         FREE(object[i]->transf);
  750.       object[i]->transf = new_transf;
  751.     }
  752.   }
  753.   if (NOT first_transf)
  754.     FREE(transf);
  755. }
  756.